package cn.tedu.charging.order.mqtt;

import cn.tedu.charging.common.pojo.JsonResult;
import cn.tedu.charging.common.pojo.param.ChargingProcessParam;
import cn.tedu.charging.common.pojo.vo.ChargingProcessVO;
import cn.tedu.charging.common.utils.JsonUtils;
import cn.tedu.charging.order.common.ChargingConstants;
import cn.tedu.charging.order.common.MqttConstants;
import cn.tedu.charging.order.common.OrderStatusConstants;
import cn.tedu.charging.order.pojo.dto.ChargingProcessDto;
import cn.tedu.charging.order.pojo.dto.ChargingResultDto;
import cn.tedu.charging.order.pojo.po.ChargingOrderFailPO;
import cn.tedu.charging.order.pojo.po.ChargingOrderSuccessPO;
import cn.tedu.charging.order.quartz.DeviceCheckJob;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.paho.client.mqttv3.*;
import org.quartz.SchedulerException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

/**
 * 用来消费 设备发送给订单服务的消息
 * 1 订阅 topic
 * 2 消费 消息
 */
@Slf4j
public class MqttConsumer implements MqttCallbackExtended {

    private MqttClient mqttClient;

    private MqttContext mqttContext;

    public MqttConsumer(MqttClient mqttClient,MqttContext mqttContext) {
        this.mqttClient = mqttClient;
        this.mqttContext = mqttContext;
    }

    /*public void setMqttClient(MqttClient mqttClient) {
        this.mqttClient = mqttClient;
    }*/

    @Override
    public void connectComplete(boolean reconnect, String serverURI) {
        log.debug("连接成功，reconnect:{},serverURI:{}",reconnect,serverURI);
        //和EMQX连接成功后， 订阅Topic
        // 1 设备返回的 开始充电 结果  TOPIC_CHARGING_RESULT
        // 2 设备同步的充电进度  TOPIC_CHARGING_PROCESS
        String topicChargingResult = MqttConstants.TOPIC_CHARGING_RESULT;
        String topicChargingProcess = MqttConstants.TOPIC_CHARGING_PROCESS;
        try {
            log.debug("订单服务 订阅 设备返回的 <<开始充电结果>> Topic:{}",topicChargingResult);
            mqttClient.subscribe(topicChargingResult);
            log.debug("订单服务 订阅 设备返回的 <<开始充电结果>> Topic:{},成功",topicChargingResult);

            log.debug("订单服务 订阅 设备同步的 <<充电进度>> Topic:{}",topicChargingProcess);
            mqttClient.subscribe(topicChargingProcess);
            log.debug("订单服务 订阅 设备同步的 <<充电进度>> Topic:{},成功",topicChargingProcess);
        } catch (MqttException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public void connectionLost(Throwable cause) {
        log.debug("连接断开，cause:{}",cause);
    }

    /**
     * 消息到达
     * 设备的消息 到达订单服务 会回调这个方法
     * @param topic name of the topic on the message was published to
     * @param message the actual message.
     * @throws Exception
     */
    @Override
    public void messageArrived(String topic, MqttMessage message) throws Exception {
        log.debug("消息到达，topic:{},message:{}",topic,message);
        if (MqttConstants.TOPIC_CHARGING_RESULT.equals(topic)) {
            log.debug("处理设备返回开始充电结果");
            handleChargingResult(message);
        }else if (MqttConstants.TOPIC_CHARGING_PROCESS.equals(topic)) {
            log.debug("处理设备同步的充电进度");
            handleChargingProcess(message);
        }
    }

    /**
     * 处理设备同步的充电进度
     * @param message
     */
    private void handleChargingProcess(MqttMessage message) {
        ChargingProcessDto chargingProcessDto = null;
        try{
            chargingProcessDto =
                    JsonUtils.fromJson(message.toString(), ChargingProcessDto.class);
        }catch (Exception e) {
            log.error("解析设备返回的消息失败,message:{}", message,e);
        }
        log.debug("收到设备同步的充电进度:{}",chargingProcessDto);
        if (chargingProcessDto != null) {
            ChargingProcessParam param = new ChargingProcessParam();
            param.setOrderNo(chargingProcessDto.getOrderNo());
            param.setGunId(chargingProcessDto.getGunId());
            log.debug("开始调用计价服务获取设备充电价格入参:{}",param);
            ChargingProcessVO chargingProcessVO = getCost(param);
            log.debug("开始调用计价服务获取设备充电价格返回入参:{},出参:{}",param,chargingProcessVO);
        }
    }

    /*
    * 通过Feign 调用计价服务，获取设备充电价格
    * */
    private ChargingProcessVO getCost(ChargingProcessParam param) {
        //通过Feign 调用计价服务，获取设备充电价格
        JsonResult <ChargingProcessVO> jsonResult =
                mqttContext.getCostClient().calculate(param);
        if (jsonResult != null){
            return jsonResult.getData();
        }
        return null;
    }

    /**
     * 处理设备返回的 开始充电结果
     * @param message
     */
    private void handleChargingResult(MqttMessage message) {
        ChargingResultDto chargingResultDto = null;
        try{
            chargingResultDto =
                    JsonUtils.fromJson(message.toString(), ChargingResultDto.class);
        }catch (Exception e) {
            log.error("解析设备返回的消息失败,message:{}", message,e);
        }
        log.debug("收到设备返回开始充电结果:{}",chargingResultDto);
        if (chargingResultDto != null) {
            //获取 设备 返回的 开始充电结果
            String result = chargingResultDto.getResult();
            if (ChargingConstants.CHARGING_RESULT_SUCCESS.equals(result)) {
                log.debug("设备发送的 开始充电成功 消息",result);
                ChargingOrderSuccessPO chargingOrderSuccessPO = new ChargingOrderSuccessPO();
                chargingOrderSuccessPO.setBillId(chargingResultDto.getOrderNo());
                //订单服务收到设备的 开始充电成功消息 后 保存成功订单记录，订单的状态为 充电中
                chargingOrderSuccessPO.setBillStatus(OrderStatusConstants.ORDER_STATUS_CHARGING);
                chargingOrderSuccessPO.setGunId(chargingResultDto.getGunId());
                log.debug("保存成功订单记录:{}",chargingOrderSuccessPO);
                int row = mqttContext.getOrderSuccessMapper().insert(chargingOrderSuccessPO);
                log.debug("保存成功订单记录:{},影响行数:{}",chargingOrderSuccessPO,row);
                //todo 设备会定时的和订单服务同步充电进度数据，直到车辆电池充满
                log.debug("设备返回了开始充电成功后，创建任务用户处理超时订单");
                handleChargingError(chargingResultDto.getOrderNo());

            }else {
                log.debug("设备发送的 开始充电失败 消息",result);
                ChargingOrderFailPO chargingOrderFailPO = new ChargingOrderFailPO();
                chargingOrderFailPO.setBillId(chargingResultDto.getOrderNo());
                //订单服务收到设备的 开始充电失败消息 后 保存失败订单记录，记录失败原因
                chargingOrderFailPO.setFailDesc("设备有响应，开始充电失败");
                chargingOrderFailPO.setGunId(chargingResultDto.getGunId());
                log.debug("保存失败订单记录:{}",chargingOrderFailPO);
                int row = mqttContext.getOrderFailMapper().insert(chargingOrderFailPO);
                log.debug("保存失败订单记录:{},影响行数:{}",chargingOrderFailPO,row);
                //todo
                log.debug("<<通知充电用户>> 更换设备");
                log.debug("<<通知充电用户>> 给用户发短信，表示歉意");
                log.debug("<<通知充电用户>> 给用户发短信，发送优惠券 营销系统，给用户心灵上的安慰");
                log.debug("<<通知设备管理员>> 对设备进行检修");
                log.debug("<<修改枪的状态为 维护中>>");
            }
        }
    }

    /**
     * 处理充电中故障
     * @param orderNo
     */
    private void handleChargingError(String orderNo) {
        log.debug("创建任务处理充电中故障");
        try {
            DeviceCheckJob deviceCheckJob = new DeviceCheckJob(orderNo);
        } catch (SchedulerException e) {
            log.error("创建任务处理充电中故障,异常:{}",e);
        }
    }

    @Override
    public void deliveryComplete(IMqttDeliveryToken token) {
        log.debug("消息发送完成，token:{}",token);
    }
}
